package com.ug_project.spring_dict.com.ug_project.spring_dict.DataAccess

import com.ug_project.spring_dict.DataAccess.Migrations.Favorites
import com.ug_project.spring_dict.DataAccess.Migrations.FavoritesInUser
import com.ug_project.spring_dict.DataAccess.Migrations.WordsInFavorite
import com.ug_project.spring_dict.DataAccess.connectDb
import com.ug_project.spring_dict.DataAccess.fillBasicData
import com.ug_project.spring_dict.DataAccess.getBasicData
import com.ug_project.spring_dict.com.ug_project.spring_dict.Entities.Favorite
import com.ug_project.spring_dict.com.ug_project.spring_dict.Entities.WordInFavorite
import com.ug_project.spring_dict.com.ug_project.spring_dict.Entities.WordItem
import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.transactions.transaction
import com.ug_project.spring_dict.com.ug_project.spring_dict.Entities.FavoritesInUser as FUser
class FavoriteRepository {
    fun insertFavorite(user: Int, fav: Favorite, accessibility: Int) : Favorite{

        transaction(connectDb()){
            val statement = Favorites.insert {
                it.fillBasicData(fav)
                it[Favorites.name] = fav.name
                it[Favorites.dictTable] = fav.langCode
                it[Favorites.creatorId] = fav.creatorId
            }
            fav.id = statement.generatedKey as Int

            val favoritesInUser = FUser(user, fav.id, true, accessibility)

            FavoritesInUser.insert {
                it.fillBasicData(favoritesInUser)
                it[FavoritesInUser.canManage] = favoritesInUser.canManage
                it[FavoritesInUser.userId] = favoritesInUser.userId
                it[FavoritesInUser.accessibility] = favoritesInUser.accessibility
                it[FavoritesInUser.favoriteID] = favoritesInUser.favoriteId
            }
        }
        return  fav
    }

    fun getAllFavorites(user: Int) : Array<Favorite>{
        val favs = transaction(connectDb()) {
            Favorites.join(FavoritesInUser, JoinType.INNER).select { FavoritesInUser.userId eq user }.adjustSlice { this.slice(Favorites.columns) } .map { it.toEntity(user) }
        }
        return favs.toTypedArray()
    }

    fun ResultRow.toEntity(userId: Int) : Favorite{
        val entity = Favorite(userId, this[Favorites.dictTable], this[Favorites.name])
        this.getBasicData(com.ug_project.spring_dict.DataAccess.Migrations.Favorites, entity)
        return entity
    }

    fun getFavoritesInUserByFavoriteId(favoriteId: Int, userId: Int) :FUser? {
        return transaction {
            FavoritesInUser.select { FavoritesInUser.favoriteID eq favoriteId and (FavoritesInUser.userId eq userId) }.firstOrNull()?.run {
                FUser(
                        this[FavoritesInUser.userId],
                        this[FavoritesInUser.favoriteID],
                        this[FavoritesInUser.canManage],
                        this[FavoritesInUser.accessibility]
                ).apply {
                    id = this@run[FavoritesInUser.id]
                }
            }
        }
    }

    fun getFavoriteById(id: Int) = transaction {
        Favorites.select { Favorites.id eq id }.firstOrNull()?.run {
            val fav = Favorite(this[Favorites.creatorId], this[Favorites.dictTable], this[Favorites.name])
            this.getBasicData(Favorites, fav)
            fav
        }
    }

    fun removeFavoritesById(Id: Int){
        transaction {
            Favorites.deleteWhere { Favorites.id eq Id }
        }
    }

    fun removeFavoritesInUserById(id: Int){
        transaction {
            FavoritesInUser.deleteWhere { FavoritesInUser.id eq id}
        }
    }

    fun removeWordsByFavoriteId(favoriteId: Int){
        transaction {
            WordsInFavorite.deleteWhere { WordsInFavorite.favoriteId eq favoriteId}
        }
    }


    fun removeFavoritesInUserByFavoriteIdAndUserId(favoriteId: Int, userId: Int){
        transaction {
            FavoritesInUser.deleteWhere { FavoritesInUser.favoriteID eq favoriteId and (FavoritesInUser.userId eq userId)}
        }
    }


    fun addToFavorites(langCode: String, favoriteId: Int, wordId: Int) : WordInFavorite{
        val wordInFavs = WordInFavorite(favoriteId, wordId)
        transaction(connectDb()) {
            WordsInFavorite.insert {
                it.fillBasicData(wordInFavs)
                it[WordsInFavorite.favoriteId] = wordInFavs.favoriteId
                it[WordsInFavorite.keyId] = wordInFavs.keyWordId
            }
        }.apply {
            wordInFavs.id = this.generatedKey as Int
        }
        return wordInFavs
    }



    fun getWordsInFavoriteByFavoriteId(favorite: Favorite): Array<WordItem>{
        return transaction(connectDb()) {
            val repo = SearchRepository()
            val table = repo.getTableByLangCode(favorite.langCode)
            WordsInFavorite.join(table, JoinType.INNER, additionalConstraint = {table.id eq WordsInFavorite.keyId}).select { WordsInFavorite.favoriteId eq favorite.id }.adjustSlice { slice(*(table.columns.toTypedArray()), WordsInFavorite.id) }.map {row ->
                WordItem(row[table.key], row[table.value], row[WordsInFavorite.id])
            }.toTypedArray()
        }
    }

    fun removeWordsInFavorites(wordId: Int) {
        transaction(connectDb()) {
            WordsInFavorite.deleteWhere { WordsInFavorite.id eq wordId }
        }
    }

    fun checkManagemenityOfWord(userId: Int, favoriteId: Int) : Boolean {
        return transaction(connectDb()) {
            FavoritesInUser.select { FavoritesInUser.userId eq userId and (FavoritesInUser.favoriteID eq favoriteId) and (FavoritesInUser.canManage eq true)  }.adjustSlice { slice(FavoritesInUser.id) }.any()
        }
    }
}

